﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public static class MathTool
{
    public static int PopCount(this int v)
    {
        int ans = 0;
        while (v!=0)
        {
            if((v&1)==1)
            ans++;
            v >>= 1;

        }
        return ans;
    }
    public static Vector2 AngleToVector(float angle)
    {
        return new Vector2(Mathf.Cos(angle / 180 * Mathf.PI), Mathf.Sin(angle / 180 * Mathf.PI));
    }
    public static float VectorToAngle(Vector2 vtr)
    {
        return Mathf.Atan2(vtr.y, vtr.x) / Mathf.PI * 180f;
    }
    public static float Cross(this Vector2 v, Vector2 t)
    {
        return v.x * t.y - v.y * t.x;
    }
    public static int PositiveMod(this int v, int md)
    {
        Debug.Assert((v >= 0) || v % md < 0);
        if (v < 0) return (v % md) + md;
        else return v % md;
    }
    public static Vector2Int ModInt(this Vector2Int vtr, int v)
    {
        return new Vector2Int(vtr.x % v, vtr.y % v);
    }
    public readonly static float gen2 = 1.414213562373095f;
    public readonly static float eps = 1e-6f;
    public static Vector2 Rotate(this Vector2 v, float angle)
    {
        if (Mathf.Abs(angle) < eps) return v;
        else if (Mathf.Abs(angle - 180) < eps) return -v;
        var r = angle / 180f * Mathf.PI;

        if (Mathf.Abs(angle - 45f) < eps)
        {
            return new Vector2(v.x - v.y, v.x + v.y) * gen2/2;
        }
        else if (Mathf.Abs(angle + 45f) < eps)
        {
            //旋转-45
            return new Vector2(v.x + v.y, - v.x + v.y) * gen2/2;
        }
        else
        {
            var sin = Mathf.Sin(r);
            var cos = Mathf.Cos(r);
            return new Vector2(v.x * cos - v.y * sin, v.x * sin + v.y * cos);
        }
    }
    public static List<Vector2> GetBoxCorner(Vector2 s, Vector2 t)
    {
        var center = (s + t) / 2;
        List<Vector2> cs = new List<Vector2> { t - center };
        for (int i = 0; i < 3; i++)
        {
            cs.Add(cs.Last().Rotate(45f));
        }
        return cs.ConvertAll(v => v + center);
    }
    public static bool IsPointInBox(Vector2 p, Vector2[] cs)
    {

        if (((cs[0] - cs[1]).Cross(p - cs[1]) * (cs[2] - cs[3]).Cross(p - cs[3]) >= 0) && ((cs[1] - cs[2]).Cross(p - cs[1]) * (cs[3] - cs[0]).Cross(p - cs[3]) >= 0)) return true;

        return false;
    }
    public static bool IsPointInBox(Vector2 p, Vector2 pos, Vector2 siz, float angle)
    {
        p -= pos;
        p = p.Rotate(-angle);
        if (Mathf.Abs(p.x) < siz.x / 2 && Mathf.Abs(p.y) < siz.y / 2)
        {
            return true;
        }
        else
        {
            return false;
        }
        //   if (((cs[0] - cs[1]).Cross(p - cs[1]) * (cs[2] - cs[3]).Cross(p - cs[3]) >= 0) && ((cs[1] - cs[2]).Cross(p - cs[1]) * (cs[3] - cs[0]).Cross(p - cs[3]) >= 0)) return true;


    }
    public static bool IsAnyPointsInBox(Vector2[] p, Vector2[] cs)
    {

        for (int i = 0; i < p.Length; i++)
        {
            if (((cs[0] - cs[1]).Cross(p[i] - cs[1]) * (cs[2] - cs[3]).Cross(p[i] - cs[3]) >= 0) && ((cs[1] - cs[2]).Cross(p[i] - cs[1]) * (cs[3] - cs[0]).Cross(p[i] - cs[3]) >= 0)) return true;
        }
        return false;


    }
    public static Vector2[] GetRectCorner(Vector2 pos, Vector2 siz, float angle)
    {
        if (Mathf.Abs(angle) < eps)
        {
            siz /= 2;
            return new Vector2[] {pos+siz,new Vector2(pos.x-siz.x,pos.y+siz.y ),pos-siz, new Vector2(pos.x + siz.x, pos.y - siz.y) };
        }
        siz /= 2;
        var ans = new Vector2[] { siz, new Vector2(-siz.x, siz.y), -siz, new Vector2(siz.x, -siz.y) };
        for (int i = 0; i < 4; i++)
        {
            ans[i] = ans[i].Rotate(angle) + pos;
        }
        return ans;
    }
    public static bool IsLineCollide(Vector2 s, Vector2 t, Vector2 a, Vector2 b)
    {
        return (s - t).Cross(a - t) * (s - t).Cross(b - t) < 0 && (a - b).Cross(s - b) * (a - b).Cross(t - b) < 0;
    }

    public static bool IsTwoRectCollide(Vector2[] ra, Vector2[] rb)

    {

        if (IsAnyPointsInBox(ra, rb) || IsAnyPointsInBox(rb, ra)) return true;

        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                var nx = i == 3 ? 0 : i + 1;
                var ny = j == 3 ? 0 : j + 1;
                if (IsLineCollide(ra[i], ra[nx], rb[j], rb[ny])) return true;
            }
        }
        return false;
    }
}
